#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <pthread.h>
#include "thread.hpp"

static int num = 5;
using namespace ThreadModle;

template<class T>
class ThreadPool
{
private:
void queue_lock()
{
    pthread_mutex_lock(&_mutex);
}
void queue_unlock()
{
    pthread_mutex_unlock(&_mutex);
}

void wakeup()
{
    pthread_cond_signal(&_cond);
}
void wakeupAll()
{
    pthread_cond_broadcast(&_cond);
}

bool IsEmpty()
{
    return _task_queue.empty();
}

void Sleep()
{
    pthread_cond_wait(&_cond,&_mutex);
}

void HanderTask(const std::string &name)
{
    while(true)
    {
        queue_lock();
        while(IsEmpty() && _Isrunning) // 任务队列为空，进入休眠
        {
            _sleep_thread_num++;
            Sleep();
            _sleep_thread_num--;
        }
        
        if(IsEmpty() && !_Isrunning) // 任务队列空，并且进程池要退出
        {
            std::cout<<name<<" quit!"<<std::endl;
            queue_unlock();
            break;
        }

        // 有任务，取出
        T t = _task_queue.front();
        _task_queue.pop();
        queue_unlock();

        // 处理任务
        t();
        std::cout<<name<<": "<< t.result() <<std::endl;
    }
}

public:
ThreadPool(int thread_num = num)
:_thread_num(thread_num)
,_sleep_thread_num(0)
,_Isrunning(false)
{
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_cond,nullptr);
}
void Init()
{
    func_t func = std::bind(&ThreadPool::HanderTask, this,std::placeholders::_1);
    for(int i=0; i<_thread_num; i++)
    {
        std::string Threadname = "Thread-"+std::to_string(i+1);
        _threads.emplace_back(Threadname, func);
    }
} 
void Start()
{
    _Isrunning = true;
    for(auto &threads : _threads)
    {
        threads.Start();
    }
}

void Push(const T &task)
{
    queue_lock();
    if(_Isrunning)
    {
        _task_queue.push(task);
        if(_sleep_thread_num > 0)
            wakeup();
    }
    queue_unlock();
}

void Stop()
{
    queue_lock();
    _Isrunning = false;
    wakeupAll();
    queue_unlock();
}

~ThreadPool()
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
}
private:
int _thread_num;

std::queue<T> _task_queue;
std::vector<Thread> _threads;

bool _Isrunning;

int _sleep_thread_num;

pthread_mutex_t _mutex;
pthread_cond_t _cond;
};